#include <avr/io.h>
//#include <avr/interrupt.h>
#include <util/delay.h>
//#include <avr/wdt.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>

#include <stdio.h>
#include "uart.h"
#include "ttybug.h"

#include "fat.h"
#include "fat_config.h"
#include "partition.h"
#include "sdcard.h"
#include "sdcard_config.h"

uint8_t print_disk_info(const struct fat_fs_struct* _fs)
{
    if(!_fs)
        return 0;

    struct sd_raw_info _disk_info;
    if(!sd_raw_get_info(&_disk_info))
        return 0;

    printf("Manuf : %#.2x\n",_disk_info.manufacturer);
    printf("Oem   : %s\n", (char *)_disk_info.oem);
    printf("Prod  : %s\n",(char*) _disk_info.product);
    printf("Rev   : %x\n", _disk_info.revision);
    printf("Serial: %ld\n", _disk_info.serial);
    printf("Date  : %d-20%.2d\n",_disk_info.manufacturing_month,_disk_info.manufacturing_year);
    printf("Size  : %ldMB\n",_disk_info.capacity / 1024 / 1024);
    printf("Copy  : %d\n", _disk_info.flag_copy);
    printf("wr/pr : %d/%d\n",_disk_info.flag_write_protect_temp,_disk_info.flag_write_protect);
    printf("Format: %d\n",_disk_info.format);
    printf("Free  : %ldMB/%ldMB",fat_get_fs_free(_fs)/1024/1024,fat_get_fs_size(_fs)/1024/1024);

    return 1;
}

uint8_t find_file_in_dir(struct fat_fs_struct* _fs, struct fat_dir_struct* _dd, const char* _name, struct fat_dir_entry_struct* _dir_entry)
{
    while(fat_read_dir(_dd, _dir_entry))
    {
        if(strcmp(_dir_entry->long_name, _name) == 0)
        {
            fat_reset_dir(_dd);
            return 1;
        }
    }

    return 0;
}

struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* _fs, struct fat_dir_struct* _dd, const char* _name)
{
    struct fat_dir_entry_struct _file_entry;
    if(!find_file_in_dir(_fs, _dd, _name, &_file_entry))
        return 0;

    return fat_open_file(_fs, &_file_entry);
}

uint32_t strtolong(const char* _str)
{
    uint32_t l = 0;
    while(*_str >= '0' && *_str <= '9')
        l = l * 10 + (*_str++ - '0');

    return l;
}


int main(){

	//<! for read global command >
	uint8_t press_key = 0;

	//<! test sd card >
	char cmd[8];			// sd card command (cd, mv, cat, dir, ls, ...)
	char arg1[20];			// sd card command argument
	char arg2[20];
	uint8_t cmd_exit = 1;	// sd card test status
	struct partition_struct* 	partition;		//partition
	struct fat_fs_struct* 		fs;				//file system
	struct fat_dir_entry_struct directory;
	struct fat_dir_struct* 		dd;				//point keep current directory
	struct fat_dir_struct* 		dd_new;			//point keep temporary directory
	struct fat_dir_entry_struct dir_entry;		//directory entry
	struct fat_dir_entry_struct file_entry;		//file entry
	struct fat_dir_entry_struct subdir_entry;
	struct fat_file_struct* 	fd;				//file struct

	uint8_t spaces;
    uint8_t file_buffer[8];
    intptr_t file_buffer_count;
    int32_t offset;



	/* Global Initialization */
	//wdt_enable(WDTO_2S);
	uart_init();
	ttybug_init();

	while(1){
		//wdt_reset();
		printf("\ncmd>");
		press_key = getchar();
		//if((press_key>0x20) && (press_key<0xa0))
		if(isalpha(press_key)){
			printf("%c", press_key);
			switch(press_key)
			{
			case 'l':
			case 'L':
				printf("\nHello!");

				break;
			case 's':
			case 'S':



				//<! SD Card Initialization >
				if(!sd_raw_init())	break;

				//<! Open disk partition >
				partition = partition_open(	sd_raw_read,
											sd_raw_read_interval,
											#if SD_RAW_WRITE_SUPPORT
											sd_raw_write,
											sd_raw_write_interval,
											#else
											0,
											0,
											#endif
											0);
				if(!partition){
					// If the partition did not open, assume the storage device
					// is a "superfloppy", i.e. has no MBR.

					partition = partition_open(	sd_raw_read,
												sd_raw_read_interval,
												#if SD_RAW_WRITE_SUPPORT
												sd_raw_write,
												sd_raw_write_interval,
												#else
												0,
												0,
												#endif
												-1);
				}
				if(!partition) 	break;

				//<! Open file system >
				fs = fat_open(partition);
				if(!fs)	break;

				//<! Open root directory >
				fat_get_dir_entry_of_path(fs, "/", &directory);
				dd = fat_open_dir(fs, &directory);
				if(!dd)	break;

				cmd_exit = 1;
				while(cmd_exit){
					printf("\n>sdcard>");
					scanf("%s",cmd);
					printf("%s ",cmd);
					//continue;
					if(strcmp(cmd,"disk")==0){			// print some card information as a boot message
						printf("\n");
						print_disk_info(fs);
					}else if(strcmp(cmd,"cd")==0){		// change directory
						// dir_name = arg
						scanf("%s",arg1);
						printf("%s",arg1);
						if(find_file_in_dir(fs, dd, &arg1[0], &subdir_entry)){
							dd_new = fat_open_dir(fs, &subdir_entry);
							if(dd_new){
								fat_close_dir(dd);
								dd = dd_new;
							}else{
								printf("\nDir not found");
							}
						}
					}else if(strcmp(cmd,"ls")==0){		// print directory listing
						printf("\n");
						while(fat_read_dir(dd, &dir_entry)){
							 spaces = sizeof(dir_entry.long_name) - strlen(dir_entry.long_name) + 4;
							 printf("%s", dir_entry.long_name);
							 printf("%c", dir_entry.attributes & FAT_ATTRIB_DIR ? '/' : ' ');
							 while(spaces--)  putchar(' ');
							 printf("%ld\n",dir_entry.file_size);
						 }
					}else if(strcmp(cmd,"cat")==0){		// search file in current directory and open it
						// file_name = arg
						scanf("%s",arg1);
						printf("%s",arg1);
						fd = open_file_in_dir(fs, dd, &arg1[0]);
						if(fd){
							// print file contents
							printf("\n");
							while((file_buffer_count = fat_read_file(fd, file_buffer, sizeof(file_buffer))) > 0){
								for(intptr_t i = 0; i < file_buffer_count; ++i){
									putchar(file_buffer[i]);
								}
							}
							fat_close_file(fd);
						}else{
							printf("\nFile not found");
						}
					}else if(strcmp(cmd,"rm")==0){		// delete file
						#if FAT_WRITE_SUPPORT
						// file_name = arg
						scanf("%s",arg1);
						printf("%s",arg1);
						if(find_file_in_dir(fs, dd, &arg1[0], &file_entry)){
							if(!fat_delete_file(fs, &file_entry)){
								printf("\nError rm");
							}
						}else{
							printf("\nFile not found");
						}
						#endif
					}else if(strcmp(cmd,"touch")==0){	// create file
						#if FAT_WRITE_SUPPORT
						// file_name = arg
						scanf("%s",arg1);
						printf("%s",arg1);
						if(!fat_create_file(dd, &arg1[0], &file_entry)){
							printf("\nError touch");
						}
						#endif
					}else if(strcmp(cmd,"mv")==0){		// move file
						#if FAT_WRITE_SUPPORT
						scanf("%s",arg1);
						printf("%s ",arg1);
						scanf("%s",arg2);
						printf("%s",arg2);
						if(find_file_in_dir(fs, dd, &arg1[0], &file_entry)){
							if(!fat_move_file(fs, &file_entry, dd, &arg2[0]))
								printf("\nError mv");
						}else{
							printf("\nFile not found");
						}
						#endif
					}else if(strcmp(cmd,"write")==0){	// Write to file
						#if FAT_WRITE_SUPPORT
						// search file in current directory and open it
						scanf("%s",arg1);
						printf("%s ",arg1);
						fd = open_file_in_dir(fs, dd, &arg1[0]);
						if(!fd)	{
							printf("Error open file\n");
						}else{
							scanf("%s",arg2);
							printf("%s",arg2);
							offset = strtolong(&arg2[0]);
							if(!fat_seek_file(fd, &offset, FAT_SEEK_SET)){
								printf("\nError seeking");
								fat_close_file(fd);
							}else{
								// read one line of text
								scanf("%s",file_buffer);
								printf("\n%s",file_buffer);
								file_buffer_count = sizeof(file_buffer);
								// write text to file
								if(fat_write_file(fd, (uint8_t*) file_buffer, file_buffer_count) != file_buffer_count){
									printf("\nError writing to file");
								}
								fat_close_file(fd);
							}
						}
						#endif
					}else if(strcmp(cmd,"mkdir")==0){
						#if FAT_WRITE_SUPPORT
						scanf("%s",arg1);
						printf("%s\n",arg1);
						if(!fat_create_dir(dd, &arg1[0], &dir_entry)){
							printf("\nError mkdir");
						}
						#endif
					}else if(strcmp(cmd,"exit")==0){
						cmd_exit = 0;
					}else{
						printf("\nUnknown SD cmd");
					}
				}
				//exit test sd card mode
				fat_close_dir(dd);			 //close directory
				fat_close(fs); 				 //close file system
				partition_close(partition);	 //close partition


				break;
			case 13:	//Enter
			case 8:		//Backspace
				break;
			default:
				printf("\nUnknown command");
			}
		}
	};
	return 0;
}
